from flask import Blueprint, request, render_template, jsonify,send_file
from flask_login import login_required, current_user
from sqlalchemy import text  # 导入 text 函数
from applications.extensions import db
from applications.models import Settings_web
from applications.schemas import Settings_webOutSchema
from applications.models import software_web
from applications.schemas import software_webOutSchema
from applications.models import kami_web
from applications.schemas import kami_webOutSchema
from applications.common.utils.http import str_to_json
from applications.common.curd import model_to_dicts
from applications.common.helper import ModelFilter
from applications.common.utils.http import fail_api, success_api, table_api
from datetime import datetime,timezone,timedelta
import os,re
import requests
import xml.etree.ElementTree as ET 
# 创建蓝图
epg_blueprint = Blueprint('epg', __name__, template_folder='templates', static_folder="static", url_prefix="/epg")

@epg_blueprint.route("/")
def index():
    nav_menu = Settings_web.query.filter(Settings_web.key_name == 'Site_Menu').first()
    # 数据格式化处理
    nav_menu = Settings_webOutSchema().dump(nav_menu).get('value_name')
    navtitle = 'EPG'

    return render_template("epg.html",user=current_user,nav_menu=str_to_json(nav_menu),navtitle=navtitle,channels=index_channel())
# 前端获取EPG真实文件e.xml下载地址
@epg_blueprint.route("/get_epg_url/e.xml")
def get_download_epg_url_e_xml():
    dt = datetime.now().strftime('%Y%m%d')
    path = os.path.dirname(os.path.abspath(__file__))+f'/channel/e_epg{dt}.xml'
    
    # 检查文件是否存在
    if not os.path.exists(path):
        return jsonify({
            'code': 404,
            'msg': '节目单文件不存在'
        }), 404
        
    try:
        return send_file(
            path,
            mimetype='application/xml',
            as_attachment=True,  # 指定为附件下载
            download_name='e.xml'  # 指定下载文件名
        )
    except Exception as e:
        return jsonify({
            'code': 500,
            'msg': f'获取文件失败: {str(e)}'
        }), 500
# 获取EPG文件
@epg_blueprint.route("/get_epg_xml")
def get_epg_xml():
    dt = datetime.now().strftime('%Y%m%d')
    from plugins.epg.tvmao import main as tvmao_main
    from plugins.epg.get_epg import main as tvsou_main
    from plugins.epg.get_epg import main as main
    # path_tvmao = os.path.dirname(os.path.abspath(__file__))+f'/channel/tvmao_{dt}.xml'
    # path_tvsou = os.path.dirname(os.path.abspath(__file__))+f'/channel/tvsou_{dt}.xml'
    path_e_epg = os.path.dirname(os.path.abspath(__file__))+f'/channel/e_epg{dt}.xml'
    
    try:
        path = path_e_epg
    except:
        # tvmao_main()
        # tvsou_main()
        main()
        return []
    return send_file(path, mimetype='application/xml')

import chardet
@epg_blueprint.route("/get_epg", methods=['GET'])
def get_epg():
    id = request.args.get('id')
    ch = request.args.get('ch')
    id = id or ch # 如果id为空，则使用ch    
    # 输入的id为空，则返回错误信息
    if not id:
        return jsonify({'code':500,'msg':'频道不能为空'})
    # 转换为小写并去除空格
    id = id.lower().strip()
    # 替换 '-'
    id = id.replace("-", "")
    id = id.replace("(", "")
    id = id.replace(")", "")
    # 替换%20
    id = id.replace("%20","")
    
    # 转换为小写并去除空格，替换特定字符
	# id = re.sub(r'[-() %]', '', id.lower().strip())
    # 处理 CCTV 的逻辑
    if "cctv" in id and "中数" not in id:
        id = get_cctv_epg_id(id)
    	
    # # 大写字母转为小写字母
    # id = id.lower()
    from plugins.epg.cctv import main as cctv_main
    dt = datetime.now().strftime('%Y%m%d')
    path = os.path.dirname(os.path.abspath(__file__))+f'/channel/cctv_{dt}.xml'
    if not os.path.exists(path):
        cctv_main()
	
		
    xml = open(path, 'r', encoding='utf-8').read()
    '''
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE tv SYSTEM "http://api.torrent-tv.ru/xmltv.dtd">
    <tv>
    <channel id="cctv1"><display-name lang="zh">CCTV-1 综合</display-name></channel>
    <programme start="20240821011100 +0800" stop="20240821013115 +0800" channel="cctv1"><title lang="zh">人口-2024-30</title><desc lang="zh"></desc></programme>
    <programme start="20240821013115 +0800" stop="20240821020115 +0800" channel="cctv1"><title lang="zh">今日说法-2024-209</title><desc lang="zh"></desc></programme>
    <programme start="20240821020115 +0800" stop="20240821023335 +0800" channel="cctv1"><title lang="zh">晚间新闻</title><desc lang="zh"></desc></programme>
    ......
    <channel id="cctv2"><display-name lang="zh">CCTV-2 财经</display-name></channel>
    ......
    </tv>
    '''
    # 解析xml,获取节目单,按频道分组
    import xml.etree.ElementTree as ET
    root = ET.fromstring(xml)
    channels = {}

    # 遍历所有节目单，获取id='cctv1'的<channel>标签数据，获取channel="cctv1"的<programme>标签数据
    for channel in root.findall('channel'):
        channel_id = channel.attrib['id']
        
        if channel_id == id:
            channels[channel_id] = []
            for programme in root.findall('programme'):
                if programme.attrib['channel'] == channel_id:
                    channels[channel_id].append(programme)
    # 判断id是否在channels中
    if id not in channels:
        return jsonify({'code':500,'msg':'频道不存在','name':id})
    # 将节目单按频道分组,按时间排序,返回json
    epg_data = []
    for channel_id, programmes in channels.items():
        programmes.sort(key=lambda x: datetime.strptime(x.attrib['start'], '%Y%m%d%H%M%S %z'))
        for programme in programmes:
            epg_data.append({
            'start': datetime.strptime(programme.attrib['start'], '%Y%m%d%H%M%S %z').strftime('%H:%M'),
            'desc': programme.find('desc').text if programme.find('desc') == 'null' else '',
            'end': datetime.strptime(programme.attrib['stop'], '%Y%m%d%H%M%S %z').strftime('%H:%M'),
            'title': programme.find('title').text if programme.find('title') is not None else "",
        })
    xml_data ={
        "code": 200,
        "msg": "请求成功",
        "name": id.upper(), 
        "tvid": id.upper(), 
        "date": datetime.now().strftime('%Y-%m-%d'), # 当前日期
        "epg_data": epg_data
    }
    # 返回json,输出为utf-8编码
    return jsonify(xml_data)
    import json
    return json.dumps(xml_data, ensure_ascii=False)
 
 
def index_channel():
    # from plugins.epg.tvmao import main as tvmao_main
    # from plugins.epg.get_epg import main as tvsou_main
    from plugins.epg.get_epg import main as tvepg_main
    
    dt = datetime.now().strftime('%Y%m%d')
    # path_tvmao = os.path.dirname(os.path.abspath(__file__))+f'/channel/tvmao_{dt}.xml'
    # path_tvsou = os.path.dirname(os.path.abspath(__file__))+f'/channel/tvsou_{dt}.xml'
    path_e_epg = os.path.dirname(os.path.abspath(__file__))+f'/channel/e_epg{dt}.xml'
    try:
        if os.path.exists(path_e_epg):
            xml = open(path_e_epg, 'r', encoding='utf-8').read()
        else:
            tvepg_main()
            xml = open(path_e_epg, 'r', encoding='utf-8').read()
    except:
        tvepg_main()
        # tvmao_main()
        # tvsou_main()
        return []
    '''
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE tv SYSTEM "http://api.torrent-tv.ru/xmltv.dtd">
    <tv>
    <channel id="cctv1"><display-name lang="zh">CCTV-1 综合</display-name></channel>
    <programme start="20240821011100 +0800" stop="20240821013115 +0800" channel="cctv1"><title lang="zh">人口-2024-30</title><desc lang="zh"></desc></programme>
    <programme start="20240821013115 +0800" stop="20240821020115 +0800" channel="cctv1"><title lang="zh">今日说法-2024-209</title><desc lang="zh"></desc></programme>
    <programme start="20240821020115 +0800" stop="20240821023335 +0800" channel="cctv1"><title lang="zh">晚间新闻</title><desc lang="zh"></desc></programme>
    ......
    <channel id="cctv2"><display-name lang="zh">CCTV-2 财经</display-name></channel>
    ......
    </tv>
    '''
    # 解析xml,获取节目单,按频道分组
    import xml.etree.ElementTree as ET
    root = ET.fromstring(xml)
    channels=[]
    current_time = datetime.now(timezone.utc).astimezone()  # 将当前时间转换为带有时区信息的时间对象
    for programme in root.findall('programme'):
        channel_id = programme.attrib['channel']
        start = datetime.strptime(programme.attrib['start'], '%Y%m%d%H%M%S %z')
        stop = datetime.strptime(programme.attrib['stop'], '%Y%m%d%H%M%S %z')
        if start <= current_time <= stop: # 如果当前时间在节目开始和结束之间
            # 检查 <title> 标签是否存在
            title_tag = programme.find('title')
            title_text = title_tag.text if title_tag is not None else "No title"
            # 检查 <desc> 标签是否存在
            desc_tag = programme.find('desc')
            desc_text = desc_tag.text if desc_tag is not None else "No description"
            channel = {
                'name': root.find(f'channel[@id="{channel_id}"]').find('display-name').text, 
                'title': title_text,
                'desc': desc_text,
                'start': start.strftime('%H:%M'),
                'end': stop.strftime('%H:%M'),
            }
            channels.append(channel)
           
    return channels
   
@epg_blueprint.route("/get_epg_tvsou", methods=['GET'])
def get_epg_tvsou():
    id = request.args.get('id')
    ch = request.args.get('ch')
    id = id or ch # 如果id为空，则使用ch    
    # 输入的id为空，则返回错误信息
    if not id:
        return jsonify({'code':500,'msg':'频道不能为空'})
    # 转换为小写并去除空格
    id = id.lower().strip()
    # 替换 '-'
    id = id.replace("-", "")
    id = id.replace("(", "")
    id = id.replace(")", "")
    # 替换%20
    id = id.replace("%20","")
    
    # 转换为小写并去除空格，替换特定字符
	# id = re.sub(r'[-() %]', '', id.lower().strip())
    # 处理 CCTV 的逻辑
    if "cctv" in id and "中数" not in id:
        id = get_cctv_epg_id(id)
    	
    # # 大写字母转为小写字母
    # id = id.lower()
    from plugins.epg.get_epg import main as tvsou_main
    dt = datetime.now().strftime('%Y%m%d')
    path = os.path.dirname(os.path.abspath(__file__))+f'/channel/tvsou_{dt}.xml'
    if not os.path.exists(path):
        tvsou_main()
		
    xml = open(path, 'r', encoding='utf-8').read()
    '''
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE tv SYSTEM "http://api.torrent-tv.ru/xmltv.dtd">
    <tv>
    <channel id="cctv1"><display-name lang="zh">CCTV-1 综合</display-name></channel>
    <programme start="20240821011100 +0800" stop="20240821013115 +0800" channel="cctv1"><title lang="zh">人口-2024-30</title><desc lang="zh"></desc></programme>
    <programme start="20240821013115 +0800" stop="20240821020115 +0800" channel="cctv1"><title lang="zh">今日说法-2024-209</title><desc lang="zh"></desc></programme>
    <programme start="20240821020115 +0800" stop="20240821023335 +0800" channel="cctv1"><title lang="zh">晚间新闻</title><desc lang="zh"></desc></programme>
    ......
    <channel id="cctv2"><display-name lang="zh">CCTV-2 财经</display-name></channel>
    ......
    </tv>
    '''
    # 解析xml,获取节目单,按频道分组
    import xml.etree.ElementTree as ET
    root = ET.fromstring(xml)
    channels = {}

    # 遍历所有节目单，获取id='cctv1'的<channel>标签数据，获取channel="cctv1"的<programme>标签数据
    for channel in root.findall('channel'):
        channel_id = channel.attrib['id']
        
        if channel_id == id:
            channels[channel_id] = []
            for programme in root.findall('programme'):
                if programme.attrib['channel'] == channel_id:
                    channels[channel_id].append(programme)
    # 判断id是否在channels中
    if id not in channels:
        return jsonify({'code':500,'msg':'频道不存在','name':id})
    # 将节目单按频道分组,按时间排序,返回json
    epg_data = []
    for channel_id, programmes in channels.items():
        programmes.sort(key=lambda x: datetime.strptime(x.attrib['start'], '%Y%m%d%H%M%S %z'))
        for programme in programmes:
            epg_data.append({
            'start': datetime.strptime(programme.attrib['start'], '%Y%m%d%H%M%S %z').strftime('%H:%M'),
            'desc': programme.find('desc').text if programme.find('desc') == 'null' else '',
            'end': datetime.strptime(programme.attrib['stop'], '%Y%m%d%H%M%S %z').strftime('%H:%M'),
            'title': programme.find('title').text if programme.find('title') is not None else "",
        })
    xml_data ={
        "code": 200,
        "msg": "请求成功",
        "name": id.upper(), 
        "tvid": id.upper(), 
        "date": datetime.now().strftime('%Y-%m-%d'), # 当前日期
        "epg_data": epg_data
    }
    # 返回json,输出为utf-8编码
    return jsonify(xml_data)
    import json
    return json.dumps(xml_data, ensure_ascii=False)
    
@epg_blueprint.route("/get_epg_tvmao", methods=['GET'])
def get_epg_tvmao():
    id = request.args.get('id')
    ch = request.args.get('ch')
    id = id or ch # 如果id为空，则使用ch    
    date = request.args.get('date')
    # 输入的id为空，则返回错误信息
    if not id:
        return jsonify({'code':500,'msg':'频道不能为空'})
    # 转换为小写并去除空格
    id = id.upper().strip()
    # 替换 '-'
    id = id.replace(" ", "")
    # from plugins.epg.tvmao import main as tvmao_main
    if date:
        # 判断date格式是否正确
        try:
            date = date.replace("-", "")
            date = date.replace("/", "")
        except ValueError:
            return jsonify({'code':500,'msg':'日期格式错误，请使用YYYYMMDD格式'})
        dt = date
    else:
        dt = datetime.now().strftime('%Y%m%d')
    path = os.path.dirname(os.path.abspath(__file__))+f'/channel/tvmao_{dt}.xml'
    if not os.path.exists(path):
        return jsonify({'code':500,'msg':'节目单不存在'})
		
    xml = open(path, 'r', encoding='utf-8').read()
    '''
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE tv SYSTEM "http://api.torrent-tv.ru/xmltv.dtd">
    <tv>
    <channel id="cctv1"><display-name lang="zh">CCTV-1 综合</display-name></channel>
    <programme start="20240821011100 +0800" stop="20240821013115 +0800" channel="cctv1"><title lang="zh">人口-2024-30</title><desc lang="zh"></desc></programme>
    <programme start="20240821013115 +0800" stop="20240821020115 +0800" channel="cctv1"><title lang="zh">今日说法-2024-209</title><desc lang="zh"></desc></programme>
    <programme start="20240821020115 +0800" stop="20240821023335 +0800" channel="cctv1"><title lang="zh">晚间新闻</title><desc lang="zh"></desc></programme>
    ......
    <channel id="cctv2"><display-name lang="zh">CCTV-2 财经</display-name></channel>
    ......
    </tv>
    '''
    # 解析xml,获取节目单,按频道分组
    import xml.etree.ElementTree as ET
    root = ET.fromstring(xml)
    channels = {}

    # 遍历所有节目单，获取id='cctv1'的<channel>标签数据，获取channel="cctv1"的<programme>标签数据
    for channel in root.findall('channel'):
        channel_id = channel.attrib['id']
        
        if channel_id == id:
            channels[channel_id] = []
            for programme in root.findall('programme'):
                if programme.attrib['channel'] == channel_id:
                    channels[channel_id].append(programme)
    # 判断id是否在channels中
    if id not in channels:
        return jsonify({'code':500,'msg':'频道不存在','name':id})
    # 将节目单按频道分组,按时间排序,返回json
    epg_data = []
    for channel_id, programmes in channels.items():
        programmes.sort(key=lambda x: datetime.strptime(x.attrib['start'], '%Y%m%d%H%M%S %z'))
        for programme in programmes:
            epg_data.append({
            'start': datetime.strptime(programme.attrib['start'], '%Y%m%d%H%M%S %z').strftime('%H:%M'),
            'desc': programme.find('desc').text if programme.find('desc') == 'null' else '',
            'end': datetime.strptime(programme.attrib['stop'], '%Y%m%d%H%M%S %z').strftime('%H:%M'),
            'title': programme.find('title').text if programme.find('title') is not None else "",
        })
    xml_data ={
        "code": 200,
        "msg": "请求成功",
        "name": id.upper(), 
        "tvid": id.upper(), 
        "date": datetime.strptime(dt, '%Y%m%d').strftime('%Y-%m-%d'),
        "epg_data": epg_data
    }
    # 返回json,输出为utf-8编码
    return jsonify(xml_data)



@epg_blueprint.route("/get_epg_url", methods=['GET'])
def get_epg_url():
    # 1. 参数验证和处理
    id = request.args.get('id') or request.args.get('ch')
    date = request.args.get('date')
    
    # 输入的id为空，则返回错误信息
    if not id:
        return jsonify({
            'code': 400,
            'msg': '频道参数不能为空'
        }), 400
    # 2. ID 规范化处理
    try:
        id = normalize_channel_id(id)
    except ValueError as e:
        return jsonify({
            'code': 400,
            'msg': str(e)
        }), 400
    # 3. 日期处理
    try:
        dt = normalize_date(date)
    except ValueError as e:
        return jsonify({
            'code': 400,
            'msg': str(e)
        }), 400
    # 4. 获取和验证 EPG 文件
    path = os.path.dirname(os.path.abspath(__file__)) + f'/channel/e_epg{dt}.xml'
    
    try:
        xml_content = get_epg_file(path)
    except FileNotFoundError:
        return jsonify({
            'code': 404,
            'msg': '节目单文件不存在'
        }), 404
    except Exception as e:
        return jsonify({
            'code': 500,
            'msg': f'获取EPG文件失败: {str(e)}'
        }), 500

    # 5. 解析 XML 并获取节目信息
    try:
        epg_data = parse_epg_data(xml_content, id)
    except Exception as e:
        return jsonify({
            'code': 500,
            'msg': f'解析EPG数据失败: {str(e)}'
        }), 500

    if not epg_data:
        return jsonify({
            'code': 404,
            'msg': '未找到该频道信息',
            'name': id
        }), 404
    # 6. 返回结果
    return jsonify({
        "code": 200,
        "msg": "请求成功",
        "name": id,
        "tvid": id,
        "date": datetime.strptime(dt, '%Y%m%d').strftime('%Y-%m-%d'),
        "epg_data": epg_data
    })
    
def normalize_channel_id(id):
    """规范化频道ID"""
    id = id.upper().strip()
    id = re.sub(r'[\s%20-]', '', id)

    if "CCTV5体育赛事" in id:
        return "CCTV5+"
    if "CGTN纪录" in id:
        return "CGTN纪录"
    if "CCTV" in id and id not in ["CCTV4欧洲", "CCTV4美洲", "CCTV4国际"]:
        id = re.sub(r'[\u4e00-\u9fa5]', '', id)

    return id
def normalize_date(date):
    """规范化日期格式"""
    if not date:
        return datetime.now().strftime('%Y%m%d')
    
    try:
        date = date.replace("-", "").replace("/", "")
        # 可以添加日期格式验证
        datetime.strptime(date, '%Y%m%d')
        return date
    except ValueError:
        raise ValueError('日期格式错误，请使用YYYYMMDD格式')

def get_epg_file(path):
    """获取EPG文件内容"""
    file_del()  # 清理旧文件
    
    if not os.path.exists(path):
        try:
            url = "https://gitee.com/taksssss/tv/raw/main/epg/112114.xml"
            response = requests.get(url)
            response.raise_for_status()
            
            raw_data = response.content
            encoding = chardet.detect(raw_data)['encoding']
            
            with open(path, 'w', encoding=encoding) as f:
                f.write(response.text)
        except Exception as e:
            raise Exception(f"下载EPG文件失败: {str(e)}")
    
    return open(path, 'r', encoding='utf-8').read()

def parse_epg_data(xml_content, channel_id):
    """解析EPG数据"""
    root = ET.fromstring(xml_content)
    epg_data = []
    
    # 查找匹配的频道
    channel_found = False
    for channel in root.findall('channel'):
        if channel.attrib['id'] == channel_id:
            channel_found = True
            break
    
    if not channel_found:
        return None
        
    # 获取节目信息
    programmes = [p for p in root.findall('programme') 
                 if p.attrib['channel'] == channel_id]
    
    # 按开始时间排序
    programmes.sort(key=lambda x: datetime.strptime(x.attrib['start'], '%Y%m%d%H%M%S %z'))
    
    for programme in programmes:
        start_time = datetime.strptime(programme.attrib['start'], '%Y%m%d%H%M%S %z')
        end_time = datetime.strptime(programme.attrib['stop'], '%Y%m%d%H%M%S %z')
        
        epg_data.append({
            'start': start_time.strftime('%H:%M'),
            'end': end_time.strftime('%H:%M'),
            'title': programme.find('title').text if programme.find('title') is not None else "",
            'desc': programme.find('desc').text if programme.find('desc') is not None else ""
        })
    
    return epg_data

# 获取 CCTV epg id 的函数
def get_cctv_epg_id(string):
	
    # if string.lower() in ['cctv14', 'cctvchild']:
    #     return 'cctvchild'
    if string.lower() in ['cctv4欧洲', 'cctv4euo']:
        return 'cctv4euo'
    if string.lower() in ['cctv4美洲', 'cctv4ame']:
        return 'cctv4ame'

    pattern = r"CCTV.*?\d+"
    match = re.search(pattern, string, re.IGNORECASE) # 忽略大小写

    if match:
        ret_str = match.group(0)  # 获取匹配的字符串

        # 检查是否包含 '+' 或 '4k'
        if '+' in string:
            ret_str += "+"
        elif "4k" in string.lower():
            ret_str += "k"

        return ret_str
    else:
        return False
        
# 多余文件处理
def file_del():
	    # 如果不准确，则需要考虑更新时覆盖问题，或者使用时间戳
    # 删除旧文件（如果存在）
    # 获取当前日期
    current_date = datetime.now()

    # 计算未来两天的日期
    dt2 = (current_date + timedelta(days=1)).strftime('%Y%m%d')
    dt3 = (current_date + timedelta(days=2)).strftime('%Y%m%d')

    # 构造文件路径
    path2 = os.path.dirname(os.path.abspath(__file__)) + f'/channel/e_epg{dt2}.xml'
    path3 = os.path.dirname(os.path.abspath(__file__)) + f'/channel/e_epg{dt3}.xml'

    # 检查文件是否存在，如果存在则删除
    try:
        if os.path.exists(path2):
            os.remove(path2)

        if os.path.exists(path3):
            os.remove(path3)
    except Exception as e:
    	pass
